﻿using System;
using System.Collections.Generic;
using ICSharpCode.AvalonEdit.Rendering;
using ICSharpCode.AvalonEdit.Document;
using System.IO;
using System.Windows.Media;
using JmShared;
using JiveMessenger.User;
using JiveMessenger.Utilities;
using System.Windows.Media.Imaging;
using JiveMessenger.ViewModels;
using JiveMessenger.Models;
using System.Windows.Controls;
using System.Web;
using System.Runtime.Caching;
using NLog;
using System.Linq;
using System.Windows;
using WpfAnimatedGif;

namespace JiveMessenger.AvalonEdit
{
    /// <summary>
    /// Implementation of AvalonEdit element generator.
    /// This class looks for image tags and produces ImageElements to visually represent those images.
    /// </summary>
    public class ImageElementGenerator : VisualLineElementGenerator
    {
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
        private Dictionary<string, IEmoticon> Emoticons { get; set; }
        private readonly bool _isWriteBox;
        private ViewModelChat _chatViewModel;
        public string DocumentID { get; set; }
        /// <summary>
        /// LineNumber as key
        /// </summary>
        public Dictionary<int, IContact> ClientLines;
        public IClient CurrentClient;
        public ImageElementGenerator(IClient currentClient, ViewModelChat chatViewModel, string id, Dictionary<int, IContact> clientLines, bool isWriteBox)
        {
            this._chatViewModel = chatViewModel;
            this.Emoticons = new Dictionary<string, IEmoticon>();
            this._isWriteBox = isWriteBox;
            this.ClientLines = clientLines;
            this.CurrentClient = currentClient;
            this.DocumentID = id;
        }
        /// <summary>
        /// Cleans the cached images for this instance from the memory cache.
        /// </summary>
        /// <param name="id"></param>
        public void CleanCache()
        {
            MemoryCache cache = MemoryCache.Default;
            List<string> cacheKeys = cache.Where(kvp => kvp.Key.Contains("ImageElementGenerator-" + this.GetHashCode())).Select(kvp => kvp.Key).ToList();
            foreach (string key in cacheKeys)
            {
                cache.Remove(key);
            }
        }

        private static KeyValuePair<int, string>? FindMatchesInStringArray(string relevantText, Dictionary<string, IEmoticon> emoticons, bool exact)
        {
            Dictionary<int, string> allMatches = new Dictionary<int, string>();

            if (exact)
            {
                if (relevantText.Length > 10)
                    relevantText = relevantText.Substring(0, 10);
                foreach (string key in emoticons.Keys)
                {
                    int i = relevantText.IndexOf(key, StringComparison.Ordinal);
                    if (i != 0)
                        continue;

                    return new KeyValuePair<int, string>(i, key);
                }
                return null;
            }
            foreach (string key in emoticons.Keys)
            {
                int i = relevantText.IndexOf(key, StringComparison.Ordinal);
                if (i != -1 && !allMatches.ContainsKey(i))
                    allMatches.Add(i, key);
            }
            KeyValuePair<int, string>? top = null;
            foreach (KeyValuePair<int, string> kvp in allMatches)
            {
                if (top.HasValue && top.Value.Key > kvp.Key)
                {
                    top = kvp;
                }
                else if (!top.HasValue)
                    top = kvp;
            }
            return top;
        }
        KeyValuePair<int, string>? GetMatch(int startOffset, bool exact)
        {
            try
            {
                DocumentLine endLine = CurrentContext.VisualLine.LastDocumentLine;
                string relevantText = CurrentContext.Document.GetText(startOffset, endLine.EndOffset - startOffset);
                if (String.IsNullOrEmpty(relevantText))
                    return null;
                IContact user;
                this.ClientLines.TryGetValue(endLine.LineNumber, out user);

                if (user != null && !this._isWriteBox)
                    this.Emoticons = this.CurrentClient.GetEmoticons(user.UserID, true, true, true);
                else
                    this.Emoticons = this.CurrentClient.GetEmoticons(this.CurrentClient.CurrentUserInfo.UserID, true, true, true);
                var matches = FindMatchesInStringArray(relevantText, this.Emoticons, exact);

                return matches;
            }
            catch (Exception ex)
            {
                Logger.ErrorException("Error getting ImageElementGenerator match", ex);
                return null;
            }
        }

        /// Gets the first offset >= startOffset where the generator wants to construct
        /// an element.
        /// Return -1 to signal no interest.
        public override int GetFirstInterestedOffset(int startOffset)
        {
            KeyValuePair<int, string>? kvp = this.GetMatch(startOffset, false);
            return kvp.HasValue ? startOffset + kvp.Value.Key : -1;
        }

        /// Constructs an element at the specified offset.
        /// May return null if no element should be constructed.
        public override VisualLineElement ConstructElement(int offset)
        {
            KeyValuePair<int, string>? kvp = this.GetMatch(offset, true);
            // check whether there's a match exactly at offset
            if (kvp.HasValue)
            {
                if (this.Emoticons.ContainsKey(kvp.Value.Value))
                {
                    IEmoticon emoticon = this.Emoticons[kvp.Value.Value];
                    string path = emoticon.EmoticonPath;
                    if (!String.IsNullOrEmpty(path))
                    {
                        string ext = VirtualPathUtility.GetExtension(path).ToLower();


                        Uri u = emoticon is JiveCustomEmoticonModel ? new Uri(path) : new Uri(String.Format("pack://application:,,,/JiveMessenger;component/{0}", path));
                        BitmapSource bitmap = StaticMethods.BitmapFromUri(u);
                        if (bitmap != null)
                        {
                            if (ext == ".gif")
                            {
                                MemoryCache cache = MemoryCache.Default;
                                string keyname = string.Format("{0}-{1}-{2}-{3}-{4}-{5}", "ImageElementGenerator", this.GetHashCode(), Window.GetWindow(base.CurrentContext.TextView).GetHashCode(), this.CurrentContext.VisualLine.LastDocumentLine.LineNumber, offset, path);
                               AnimatedEmoticonImage image = cache.Get(keyname) as AnimatedEmoticonImage;
                                if (image == null || !image.IsLoaded)
                                {
                                    if (image != null)
                                    {
                                        cache.Remove(keyname);
                                        image = null;
                                    }
                                    image = new AnimatedEmoticonImage(bitmap, _chatViewModel, CurrentClient, path, kvp.Value.Value);
                                    image.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;

                                    CacheItemPolicy policy = new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0, 2, 0) };
                                    cache.Add(keyname, image, policy);
                                    Logger.Trace("Created new emoticon image for {0}", path);
                                }
                              //  image.SetAnimatedSource(image.Source);
                                var controller = WpfAnimatedGif.ImageBehavior.GetAnimationController(image);
                                if (controller != null)
                                {
                                    if (CurrentClient.UserSettings.AnimateGifEmoticons.GetValueOrDefault() == true
                                        && (_chatViewModel.IsFocused || CurrentClient.UserSettings.PauseEmoticonsOnFocusLoss.GetValueOrDefault() == false))
                                    {
                                        //   WpfAnimatedGif.ImageBehavior.SetAutoStart(image, true);
                                        controller.Play();
                                    }
                                    else
                                    {

                                        controller.Pause();
                                    }
                                }
                                // Pass the length of the match to the 'documentLength' parameter
                                // of InlineObjectElement.
                                InlineObjectElement imgElement = new InlineObjectElement(kvp.Value.Value.Length, image);

                                return imgElement;
                            }
                            else
                                return new ImageElement(bitmap, CurrentClient, path, kvp.Value.Value, kvp.Value.Value.Length);
                            //else
                            //{
                            //    image.SetAnimatedSource(image.Source, CurrentClient.UserSettings.AnimateGifEmoticons.GetValueOrDefault());
                            //    if (CurrentClient.UserSettings.AnimateGifEmoticons.GetValueOrDefault())
                            //    {
                            //        ImageAnimationController control = ImageBehavior.GetAnimationController(image);
                            //        if (control != null)
                            //        {
                            //            control.Play();
                            //        }
                            //    }
                            //}

                            // image.SetAnimatedSource(image.Source as BitmapSource, CurrentClient.UserSettings.AnimateGifEmoticons.GetValueOrDefault());


                        }
                    }
                }
            }
            return null;
        }
    }
}
